package org.homonoia.controller.core;

import java.io.IOException;
import java.util.Scanner;

import org.apache.commons.daemon.Daemon;
import org.apache.commons.daemon.DaemonContext;
import org.apache.commons.daemon.DaemonInitException;
import org.apache.log4j.Logger;
import org.homonoia.controller.exceptions.StartupException;
import org.homonoia.controller.net.SocketConnectionListener;

public class ControllerNodeLauncher implements Daemon {

    private static final Logger log = Logger.getLogger(ControllerNodeLauncher.class);

    private SocketConnectionListener connectionListener = null;
    private Thread listenThread = null;
    private Thread serviceThread = null;
    private ControllerNodeService controllerNodeService = null;
    private static ControllerNodeLauncher controllerNodeLauncherInstance = new ControllerNodeLauncher();

    /**
     * @param args
     */
    public static void main(String[] args) {
	try {
	    controllerNodeLauncherInstance.initialize();
	    controllerNodeLauncherInstance.run();
	} catch (StartupException e) {
	    System.out.printf(e.getMessage());
	    System.exit(1);
	}

	Scanner sc = new Scanner(System.in);

	System.out.printf("Enter 'stop' to halt: ");

	while (!sc.nextLine().toLowerCase().equals("stop"))
	    ;

	sc.close();

	controllerNodeLauncherInstance.halt();
	controllerNodeLauncherInstance.terminate();
    }

    public void init(DaemonContext context) throws DaemonInitException, Exception {
	initialize();
    }

    public void start() throws Exception {
	run();
    }

    public void stop() throws Exception {
	halt();
    }

    public void destroy() {
	terminate();
    }

    private void initialize() throws StartupException {
	log.info("***********************************");
	log.info("*** --- Homonoia Controller --- ***");
	log.info("*** ---     Version 0.2     --- ***");
	log.info("***********************************");

	if (controllerNodeService == null) {
	    controllerNodeService = new ControllerNodeService();
	    try {
		controllerNodeService.loadConfiguration();
		controllerNodeService.initializeManagers();
	    } catch (StartupException e) {
		controllerNodeService = null;
		throw e;
	    }

	    try {
		connectionListener = new SocketConnectionListener(controllerNodeService);
	    } catch (NumberFormatException e) {
		log.error(e.getMessage(), e);
		return;
	    } catch (IOException e) {
		log.error(e.getMessage(), e);
		return;
	    }
	} else {
	    log.error("Service Already Started. Please call 'stop' before attempting to start the service");
	    throw new StartupException(
		    "Service Already Started. Please call 'stop' before attempting to start the service");
	}

	log.info("Homonoia Controller Initialized");
    }

    private void run() {
	log.info("Starting Service");

	serviceThread = new Thread(controllerNodeService);
	serviceThread.start();

	listenThread = new Thread(connectionListener);
	listenThread.start();
    }

    private void halt() {
	log.info("Halting Service");

	if (!connectionListener.isStopped()) {
	    try {
		connectionListener.stop();
	    } catch (IOException e) {
		log.error(e.getMessage(), e);
	    }
	}

	try {
	    if (listenThread.isAlive()) {
		listenThread.join();
	    }
	} catch (Exception e) {
	    log.error(e.getMessage(), e);
	}

	if (!controllerNodeService.isStopped()) {
	    controllerNodeService.stop();
	}

	try {
	    if (serviceThread.isAlive()) {
		serviceThread.join();
	    }
	} catch (Exception e) {
	    log.error(e.getMessage(), e);
	}

	log.info("Halted Service");
    }

    private void terminate() {
	log.info("Homonoia Controller Terminating");

	connectionListener = null;
	listenThread = null;
	serviceThread = null;
	controllerNodeService = null;

	log.info("Homonoia Controller Terminated");
    }
}
